package com.louis.dao;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.stereotype.Repository;

import com.louis.domain.DomainObject;

/**
 * 
 * @author louis
 * 
 */
@Repository("generalDao")
public class HibernateGeneralDao extends HibernateDaoSupport implements GeneralDao {

	@Resource(name = "sessionFactory")
	public void setSuperSessionFactory(SessionFactory sessionFactory) {
		super.setSessionFactory(sessionFactory);
	}

	/**
	 * @see com.louis.dao.GeneralDao#saveOrUpdate(com.louis.domain.DomainObject)
	 */
	@Override
	public <T extends DomainObject> void saveOrUpdate(T domainObject) throws DataAccessException {
		getHibernateTemplate().saveOrUpdate(domainObject);
	}

	/**
	 * @see com.louis.dao.GeneralDao#saveOrUpdate(java.util.List)
	 */
	@Override
	public void saveOrUpdate(List<? extends DomainObject> domainObjects) throws DataAccessException {
		getHibernateTemplate().saveOrUpdateAll(domainObjects);
	}

	/**
	 * @see com.louis.dao.GeneralDao#delete(com.louis.domain.DomainObject)
	 */
	@Override
	public void delete(DomainObject domainObject) throws DataAccessException {
		getHibernateTemplate().delete(domainObject);
	}

	/**
	 * @see com.louis.dao.GeneralDao#delete(java.util.List)
	 */
	@Override
	public void delete(List<? extends DomainObject> domainObjects) throws DataAccessException {
		getHibernateTemplate().deleteAll(domainObjects);
	}

	/**
	 * @see com.louis.dao.GeneralDao#delete(java.lang.Class, java.io.Serializable)
	 */
	@Override
	public void delete(Class<? extends DomainObject> clazz, Serializable id) throws DataAccessException {
		delete(get(clazz, id));
	}

	/**
	 * @see com.louis.dao.GeneralDao#delete(java.lang.Class, java.util.List)
	 */
	@Override
	public void delete(Class<? extends DomainObject> clazz, List<Serializable> ids) throws DataAccessException {
		delete(get(clazz, ids));
	}

	/**
	 * @see com.louis.dao.GeneralDao#load(java.lang.Class, java.io.Serializable)
	 */
	@Override
	public <T extends DomainObject> T load(Class<T> clazz, Serializable id) throws DataAccessException {
		return getHibernateTemplate().load(clazz, id);
	}

	/**
	 * @see com.louis.dao.GeneralDao#load(java.lang.Class, java.util.List)
	 */
	@Override
	public <T extends DomainObject> List<T> load(Class<T> clazz, List<Serializable> ids) throws DataAccessException {
		List<T> list = new ArrayList<T>();
		T t = null;
		for (Serializable id: ids) {
			t = load(clazz, id);
			list.add(t);
		}
		return list;
	}

	/**
	 * @see com.louis.dao.GeneralDao#get(java.lang.Class, java.io.Serializable)
	 */
	@Override
	public <T extends DomainObject> T get(Class<T> clazz, Serializable id) throws DataAccessException {
		return getHibernateTemplate().get(clazz, id);
	}

	/**
	 * @see com.louis.dao.GeneralDao#get(java.lang.Class, java.util.List)
	 */
	@Override
	public <T extends DomainObject> List<T> get(final Class<T> clazz, final List<Serializable> ids) throws DataAccessException {
		return getHibernateTemplate().execute(new HibernateCallback<List<T>>() {
			@SuppressWarnings("unchecked")
			@Override
			public List<T> doInHibernate(Session session) throws HibernateException, SQLException {
				return session.createQuery("from " + clazz.getName() + " do where do.id in(:ids)").setParameterList("ids", ids).list();
			}
		});
	}

	/**
	 * @see com.louis.dao.GeneralDao#query(java.lang.Class, boolean)
	 */
	@Override
	public <T extends DomainObject> List<T> query(final Class<T> clazz, final boolean cacheable) throws DataAccessException {
		return getHibernateTemplate().execute(new HibernateCallback<List<T>>() {
			@SuppressWarnings("unchecked")
			@Override
			public List<T> doInHibernate(Session session) throws HibernateException, SQLException {
				return session.createQuery("from " + clazz.getName() + " do").setCacheable(cacheable).list();
			}
		});
	}

	/**
	 * @see com.louis.dao.GeneralDao#query(java.lang.Class, java.lang.String, java.util.Map, boolean)
	 */
	@Override
	public <T extends DomainObject> List<T> query(Class<T> clazz, final String hql, final Map<String, Object> parameters, final boolean cacheable) throws DataAccessException {
		return getHibernateTemplate().execute(new HibernateCallback<List<T>>() {
			@SuppressWarnings("unchecked")
			@Override
			public List<T> doInHibernate(Session session) throws HibernateException, SQLException {
				return session.createQuery(hql).setProperties(parameters).setCacheable(cacheable).list();
			}
		});
	}

	/**
	 * @see com.louis.dao.GeneralDao#query(java.lang.Class, int, int, boolean)
	 */
	@Override
	public <T extends DomainObject> List<T> query(final Class<T> clazz, final int pageSize, final int firstResult, final boolean cacheable) throws DataAccessException {
		return getHibernateTemplate().execute(new HibernateCallback<List<T>>() {
			@SuppressWarnings("unchecked")
			@Override
			public List<T> doInHibernate(Session session) throws HibernateException, SQLException {
				return session.createQuery("from " + clazz.getName() + " do").setMaxResults(pageSize).setFirstResult(firstResult).setCacheable(cacheable).list();
			}
		});
	}

	/**
	 * @see com.louis.dao.GeneralDao#query(java.lang.Class, java.lang.String, java.util.Map, int, int, boolean)
	 */
	@Override
	public <T extends DomainObject> List<T> query(final String hql, final Map<String, Object> parameters, final int pageSize, final int firstResult, final boolean cacheable)
			throws DataAccessException {
		return getHibernateTemplate().execute(new HibernateCallback<List<T>>() {
			@SuppressWarnings("unchecked")
			@Override
			public List<T> doInHibernate(Session session) throws HibernateException, SQLException {
				return session.createQuery(hql).setProperties(parameters).setMaxResults(pageSize).setFirstResult(firstResult).setCacheable(cacheable).list();
			}
		});
	}

	/**
	 * @see com.louis.dao.GeneralDao#count(java.lang.Class)
	 */
	@SuppressWarnings("unchecked")
	@Override
	public int count(Class<? extends DomainObject> clazz) throws DataAccessException {
		List<Integer> find = getHibernateTemplate().find("select count(*) from " + clazz.getName() + " do");
		return find.get(0);
	}

	/**
	 * @see com.louis.dao.GeneralDao#count(java.lang.String, java.util.Map)
	 */
	@Override
	public int count(final String hql, final Map<String, Object> parameters) throws DataAccessException {
		return getHibernateTemplate().execute(new HibernateCallback<Integer>() {
			@Override
			public Integer doInHibernate(Session session) throws HibernateException, SQLException {
				Object uniqueResult = session.createQuery(hql).setProperties(parameters).uniqueResult();
				return Integer.parseInt(uniqueResult.toString(), 0);
			}
		});
	}

	/**
	 * @see com.louis.dao.GeneralDao#query(java.lang.String, java.util.Map)
	 */
	@Override
	public <T extends DomainObject> List<T> query(Class<T> clazz, final String hql, final Map<String, Object> parameters) {
		return getHibernateTemplate().execute(new HibernateCallback<List<T>>() {
			@SuppressWarnings("unchecked")
			@Override
			public List<T> doInHibernate(Session session) throws HibernateException, SQLException {
				return session.createQuery(hql).setProperties(parameters).list();
			}
		});
	}

}
